﻿
using ARchGL.Declaration.Platform.Service;
using ARchGL.Declaration.Platform.Service.Utils;
using ARchGL.Declaration.Platform.Web.Models.Api;
using log4net;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Script.Serialization;
using TDF.Core.Configuration;
using TDF.Core.Log;
using TDF.Core.Models;


namespace ARchGL.Declaration.Platform.Web.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class ApiSecurityFilter : ActionFilterAttribute
    {
        public ILog Log => LogFactory.GetLogger(GetType());
        /// <summary>
        /// 
        /// </summary>
        public BaseService BaseService = new BaseService();

        static List<string> debugAddressList = new List<string> {
            "10.45.0.37","10.45.0.38","10.45.0.49",
            "10.45.4.168","192.168.137.1","192.168.23.1",//公司开发机
            "192.168.31.106","192.168.31.139",//笔记本
        };

        static List<string> asfad = new List<string>
        {
            "FindToken",
            "GetToken",
            "FindAccessToken",
        };

        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            var request = actionContext.Request;
            string openid = string.Empty, timestamp = string.Empty, random = string.Empty, signature = string.Empty, loginToken = string.Empty;
            ApiResult result = new ApiResult();

            //if (request.Headers.Contains("logintoken"))
            //{
            //    loginToken = HttpUtility.UrlDecode(request.Headers.GetValues("logintoken").FirstOrDefault());

            //    //if (string.IsNullOrWhiteSpace(loginToken))
            //    //throw new KnownException("帐号已存在，请重新输入");
            //    //BaseService.GetSessionByToken(loginToken);

            //    //result.Code = StatusCodeEnum.ParameterError.GetHashCode();
            //    //result.Fail(StatusCodeEnum.ParameterError.GetEnumText());

            //    //actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
            //}
            base.OnActionExecuting(actionContext);
            return;

            try
            {
                var localAddress = SystemHelper.GetLocalIpv4();
                if (localAddress.Length > 12)//单机多 IP
                {
                    foreach (var item in localAddress.Split(','))
                    {
                        if (debugAddressList.Contains(item) || item.Contains("10.45.4."))
                        {
                            base.OnActionExecuting(actionContext);
                            return;
                        }
                    }
                }
                else if (debugAddressList.Contains(localAddress) || debugAddressList.Contains("10.45.4."))
                {//本地调试不需要 Token 
                    base.OnActionExecuting(actionContext);
                    return;
                }



                string method = request.Method.Method;

                var actionName = actionContext.ActionDescriptor.ActionName;

                if (request.Headers.Contains("openid"))
                {
                    openid = HttpUtility.UrlDecode(request.Headers.GetValues("openid").FirstOrDefault());
                }
                if (request.Headers.Contains("timestamp"))
                {
                    timestamp = HttpUtility.UrlDecode(request.Headers.GetValues("timestamp").FirstOrDefault());
                }
                if (request.Headers.Contains("random"))
                {
                    random = HttpUtility.UrlDecode(request.Headers.GetValues("random").FirstOrDefault());
                }
                if (request.Headers.Contains("signature"))
                {
                    signature = HttpUtility.UrlDecode(request.Headers.GetValues("signature").FirstOrDefault());
                }
                Log.Debug($"actionName={actionName}, openid={openid}, timestamp={timestamp}, random={random}, signature={signature}");

                //GetToken方法不需要进行签名验证
                if (asfad.Contains(actionName))//从登录方法中获取 Token
                {
                    if (actionName != "FindAccessToken" && (string.IsNullOrEmpty(openid) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(random)))
                    {
                        result.Code = StatusCodeEnum.ParameterError.GetHashCode();
                        result.Fail(StatusCodeEnum.ParameterError.GetEnumText());

                        actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                        base.OnActionExecuting(actionContext);
                        return;
                    }
                    else
                    {
                        base.OnActionExecuting(actionContext);
                        return;
                    }
                }

                //判断请求头是否包含以下参数
                if (string.IsNullOrEmpty(openid) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(random) || string.IsNullOrEmpty(signature))
                {
                    result.Code = StatusCodeEnum.ParameterError.GetHashCode();
                    result.Fail(StatusCodeEnum.ParameterError.GetEnumText());

                    actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                    base.OnActionExecuting(actionContext);
                    return;
                }

                ////判断timespan是否有效
                //long ts1 = 0;
                ////double ts2 = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds;
                //bool timespanvalidate = long.TryParse(timestamp, out ts1);
                ////double ts = ts2 - ts1;
                //bool falg = ts1 < DateTime.UtcNow.GetTotalMilliseconds();
                //if (falg || (!timespanvalidate))
                //{
                //    result = new TDF.Web.Models.JsonResult();
                //    result.Fail(StatusCodeEnum.URLExpireError.GetEnumText());

                //    actionContext.Response = HttpResponseExtension.ToJson(JsonConvert.SerializeObject(result));
                //    base.OnActionExecuting(actionContext);
                //    return;
                //}

                //判断token是否有效
                var token = (Token)HttpRuntime.Cache.Get(openid);
                string signtoken = string.Empty;
                if (token == null)
                {
                    result.Code = StatusCodeEnum.TokenInvalid.GetHashCode();
                    result.Fail(StatusCodeEnum.TokenInvalid.GetEnumText());

                    actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                    base.OnActionExecuting(actionContext);
                    return;
                }
                else
                {
                    signtoken = token.Token;

                    if (DateTime.UtcNow > token.ExpireTime)
                    {// Token 过期
                        result.Code = StatusCodeEnum.URLExpireError.GetHashCode();
                        result.Fail(StatusCodeEnum.URLExpireError.GetHashCode().ToString());

                        actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                        base.OnActionExecuting(actionContext);
                        return;
                    }
                }

                //根据请求类型拼接参数
                NameValueCollection form = HttpContext.Current.Request.QueryString;
                string data = string.Empty;
                var tempdata = string.Empty;
                switch (method)
                {
                    case "POST":
                        //var stream = HttpContext.Current.Request.InputStream;
                        //string responseJson = string.Empty;
                        //var streamReader = new StreamReader(stream);
                        //data = streamReader.ReadToEnd();
                        var task = actionContext.Request.Content.ReadAsStreamAsync();
                        using (var sm = task.Result)
                        {
                            if (sm != null)
                            {
                                sm.Seek(0, SeekOrigin.Begin);
                                int len = (int)sm.Length;
                                byte[] inputByts = new byte[len];
                                sm.Read(inputByts, 0, len);
                                sm.Close();
                                tempdata = HttpUtility.UrlDecode(Encoding.UTF8.GetString(inputByts));
                            }
                        }
                        Log.Debug($"POST, Uri={request.RequestUri}, Data={tempdata}");
                        //data = HttpUtility.UrlDecode(actionContext.Request.Content.ReadAsStringAsync().Result);

                        if (!string.IsNullOrWhiteSpace(tempdata) && tempdata.Contains("="))
                        {
                            if (tempdata.Substring(0, 8).Contains("="))
                            {
                                var length = tempdata.IndexOf('=') + 1;
                                data = tempdata.Substring(length, tempdata.Length - length);
                            }
                            else
                            {
                                data = tempdata;
                            }
                        }
                        else
                        {
                            data = tempdata;
                        }
                        break;
                    case "GET":
                        {
                            //第一步：取出所有get参数
                            IDictionary<string, string> parameters = new Dictionary<string, string>();
                            for (int f = 0; f < form.Count; f++)
                            {
                                string key = form.Keys[f];
                                parameters.Add(key, form[key]);
                            }

                            // 第二步：把字典按Key的字母顺序排序
                            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
                            IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();

                            // 第三步：把所有参数名和参数值串在一起
                            var query = new StringBuilder();
                            while (dem.MoveNext())
                            {
                                string key = dem.Current.Key;
                                string value = dem.Current.Value;
                                if (!string.IsNullOrEmpty(key))
                                {
                                    query.Append(key).Append(value);
                                }
                            }
                            data = query.ToString();
                            break;
                        }
                    default:
                        result.Code = StatusCodeEnum.HttpMehtodError.GetHashCode();
                        result.Fail(StatusCodeEnum.HttpMehtodError.GetEnumText());

                        actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                        base.OnActionExecuting(actionContext);
                        return;
                }

                bool validateResult = Validate(timestamp, random, openid, signtoken, data, signature);
                if (!validateResult)
                {
                    result.Code = StatusCodeEnum.HttpRequestError.GetHashCode();
                    result.Fail(StatusCodeEnum.HttpRequestError.GetEnumText());

                    actionContext.Response = ToJson(JsonConvert.SerializeObject(result));
                    base.OnActionExecuting(actionContext);
                    return;
                }
                else
                {
                    base.OnActionExecuting(actionContext);
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Filter 异常", ex);
            }
        }

        /// <summary>
        /// Converto JSON
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public HttpResponseMessage ToJson(Object obj)
        {
            String str;
            if (obj is String || obj is Char)
            {
                str = obj.ToString();
            }
            else
            {
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                str = serializer.Serialize(obj);
            }
            return new HttpResponseMessage
            {
                Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json")
            };
        }

        /// <summary>
        /// 签证签名
        /// </summary>
        /// <param name="timeStamp">时间戳</param>
        /// <param name="random">随机数</param>
        /// <param name="openid"></param>
        /// <param name="token"></param>
        /// <param name="data"></param>
        /// <param name="signature">数字签名</param>
        /// <returns></returns>
        public static bool Validate(string timeStamp, string random, string openid, string token, string data, string signature)
        {
            //拼接签名数据，并加上干扰码（干扰码是线下约定的）
            var signStr = timeStamp + random + openid + token + data + "a7273bce-23a1-450d-902d-7c30a4456635";
            //将字符串中字符按升序排序
            var sortStr = string.Concat(signStr.OrderBy(c => c));

            //使用MD5加密，并验证是否相等
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sortStr, "MD5").ToLower() == signature.ToLower();
        }
    }
}